package com.heima.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.user.dtos.UserDto;
import com.heima.user.dtos.UserFollowDto;
import com.heima.common.constants.UserConstants;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.feign.wemedia.WemediaClient;
import com.heima.model.common.dtos.PageRequestDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.user.context.BaseContext;
import com.heima.user.dtos.LoginDto;
import com.heima.user.dtos.LoginResDto;
import com.heima.user.mapper.ApUserFanMapper;
import com.heima.user.mapper.ApUserFollowMapper;
import com.heima.user.pojos.ApUser;
import com.heima.user.pojos.ApUserFan;
import com.heima.user.pojos.ApUserFollow;
import com.heima.user.pojos.ApUserRealname;
import com.heima.user.service.ApUserRealnameService;
import com.heima.user.service.ApUserService;
import com.heima.user.mapper.ApUserMapper;
import com.heima.utils.common.AppJwtUtil;
import com.heima.utils.common.MD5Utils;
import com.heima.wemedia.dtos.WmAuthDto;
import com.heima.wemedia.pojos.WmUser;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

import static com.heima.model.common.enums.AppHttpCodeEnum.*;

/**
 * @author 郭文杰
 * @description 针对表【ap_user(APP用户信息表)】的数据库操作Service实现
 * @createDate 2023-12-01 16:11:10
 */
@Service
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser>
        implements ApUserService {

    @Autowired
    private ApUserRealnameService apUserRealnameService;

    @Autowired
    private ApUserService apUserService;

    @Autowired
    private WemediaClient wemediaClient;

    @Autowired
    private ApUserFollowMapper apUserFollowMapper;

    @Autowired
    private ApUserFanMapper apUserFanMapper;

    @Autowired
    private ApUserMapper apUserMapper;

    @Autowired
    private CacheService cacheService;


    @Override
    public LoginResDto loginAuth(LoginDto loginDto) {
        //脱敏数据 返回对象
        LoginResDto loginResDto = new LoginResDto();

        //获取用户名和密码
        String phone = loginDto.getPhone();
        String password = loginDto.getPassword();

        //判断用户名和密码是否为空
        //1 如果 都为null 游客登录
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(password)) {
            // 未登录设置用户id为0
            String token = AppJwtUtil.getToken(0L);
            loginResDto.setToken(token);
        } else {
            //2 如果 用户名或密码为null 用户登录
            if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password)) {
                //用户名或密码为null抛出异常
                throw new CustomException(LOGIN_PASSWORD_OR_PHONE_EMPTY);
            }
            //2.1 判断用户是否存在
            LambdaQueryWrapper<ApUser> queryMapper = new LambdaQueryWrapper<>();
            queryMapper.eq(ApUser::getPhone, loginDto.getPhone()).eq(ApUser::getStatus, 0);
            ApUser user = this.getOne(queryMapper);
            //用户不存在,抛出异常
            if (user == null) {
                throw new CustomException(AP_USER_DATA_NOT_EXIST);
            }
            //2.2 判断密码是否正确
            //生成加密密码 输入密码+salt
            String inputPassword = MD5Utils.encodeWithSalt(password, user.getSalt());
            if (!inputPassword.equals(user.getPassword())) {
                //密码不正确,抛出异常
                throw new CustomException(LOGIN_PASSWORD_ERROR);
            }

            //3 用户名 密码正确 返回jwt
            //获取请求头
            String token = AppJwtUtil.getToken(user.getId());

            user.setPassword("******");
            user.setPhone("******");
            loginResDto.setToken(token);
            loginResDto.setUser(user);

        }

        //返回对象
        return loginResDto;
    }

    /**
     * 用户审核 分页查询
     *
     * @param pageRequestDto 前端dto 分页查询参数 页码 每页显示条数 条件
     * @return 返回结果
     */
    @Override
    public Page authPage(PageRequestDto pageRequestDto) {
        if (pageRequestDto.getPage() == null || pageRequestDto.getSize() == null) {
            throw new CustomException(PARAM_REQUIRE);
        }
        Page<ApUserRealname> page = new Page<>(pageRequestDto.getPage(), pageRequestDto.getSize());
        LambdaQueryWrapper<ApUserRealname> wrapper = new LambdaQueryWrapper<>();
        if (pageRequestDto.getStatus() != null) {
            wrapper.eq(ApUserRealname::getStatus, pageRequestDto.getStatus());
        }
        apUserRealnameService.page(page, wrapper);
        return page;
    }

    /**
     * 用户审核通过
     *
     * @param wmAuthDto 前端dto 开通自媒体账号的信息
     */
    @Override
    public void authPass(WmAuthDto wmAuthDto) {
        if (wmAuthDto.getId() == null) {
            throw new CustomException(PARAM_REQUIRE);
        }
        //查询未通过审核用户 select * from ap_user_realname where id = '';
        LambdaQueryWrapper<ApUserRealname> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApUserRealname::getId, wmAuthDto.getId());
        ApUserRealname userRealname = apUserRealnameService.getOne(wrapper);
        //查询未通过审核用户的用户id在自媒体用户中是否存在
        WmUser wmUser = new WmUser();
        wmUser.setApUserId(userRealname.getUserId());

        //判断自媒体用户是否存在前,先根据app端用户id查询
        ResponseResult result = wemediaClient.getUser(wmUser);
        wmUser = (WmUser) result.getData();
        if (wmUser == null) {
            //如果不存在,然后根据app端用户名称查询
            // select * from ap_user where id = ap_user_realname.getUserId();
            wmUser = new WmUser();
            LambdaQueryWrapper<ApUser> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.eq(ApUser::getId, userRealname.getUserId());
            ApUser apUser = apUserService.getOne(wrapper2);
            wmUser.setName(apUser.getName());
            result = wemediaClient.getUser(wmUser);
            wmUser = (WmUser) result.getData();
            if (wmUser != null) {
                // 如果根据app端用户名称查询的用户存在,则自媒体账号已经开通,修改通过审核,设置关联的app用户id
                updateApUserRealname(wmAuthDto);
                WmUser updWmUser = new WmUser();//更新之后的WmUser
                updWmUser.setApUserId(Integer.valueOf(apUser.getId() + ""));
                updWmUser.setId(wmUser.getId());
                // update ap_user set ap_user_id = apUser.getId() where id = '';
                wemediaClient.updateUser(updWmUser);//自媒体用户关联的app用户id
            } else {
                //如果app端用户id和app端用户名称都不存在,直接使用app端用户开通自媒体用户
                WmUser newWmUser = new WmUser();
                newWmUser.setApUserId(apUser.getId().intValue());
                newWmUser.setName(apUser.getName());
                newWmUser.setPassword(apUser.getPassword());
                newWmUser.setSalt("123");
                newWmUser.setStatus(9);
                newWmUser.setCreatedTime(new Date());
                newWmUser.setPhone(apUser.getPhone());
                wemediaClient.save(newWmUser);
                updateApUserRealname(wmAuthDto);
            }
        }
    }

    /**
     * 平台管理用户 审核通过
     *
     * @param wmAuthDto 修改的信息
     */
    private void updateApUserRealname(WmAuthDto wmAuthDto) {
        LambdaUpdateWrapper<ApUserRealname> wrapper2 = new LambdaUpdateWrapper<>();
        wrapper2.set(ApUserRealname::getStatus, "9")
                .set(ApUserRealname::getReason, "审核通过")
                .eq(ApUserRealname::getId, wmAuthDto.getId());
        apUserRealnameService.update(wrapper2);
    }

    /**
     * 用户审核驳回
     *
     * @param wmAuthDto 前端dto
     */
    @Override
    public void authFail(WmAuthDto wmAuthDto) {
        if (wmAuthDto.getMsg() == null) {
            throw new CustomException(PARAM_REQUIRE);
        }
        LambdaUpdateWrapper<ApUserRealname> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(ApUserRealname::getReason, wmAuthDto.getMsg())
                .eq(ApUserRealname::getId, wmAuthDto.getId());

        apUserRealnameService.update(wrapper);
    }

    /**
     * <h2>用户关注与取消</h2>
     *
     * @param userFollowDto 前端dto<br>
     *                      operation:  0关注 1取消
     */
    @Override
    @Transactional
    public void userFollow(UserFollowDto userFollowDto) {
        //参数校验
        if (userFollowDto == null || userFollowDto.getAuthorId() == null
                || userFollowDto.getArticleId() == null || userFollowDto.getOperation() == null) {
            return;
        }
        //判断用户是否登录
        Long userId = BaseContext.getCurrentId();
        if (userId == 0) {
            throw new CustomException(NEED_LOGIN);
        }
        //判断当前用户是否关注到自己的文章
        if (userFollowDto.getAuthorId() == userId.intValue()) {
            throw new CustomException(USER_FOLLOW_ERROR);
        }

        String followUserId = userId.toString();
        String fansUserId = userFollowDto.getAuthorId().toString();
        Short operation = userFollowDto.getOperation();
        //更新数据库关注与被关注
        // updDbFollow(userFollowDto, userId);
        //更新redis
        //用户关注key设计: zset类型 key:业务前缀_用户id value:关注用户id score:当前时间戳
        String followKey = UserConstants.USER_FOLLOW_LIST + "_" + userId;
        /*LambdaQueryWrapper<ApUserFollow> userFollowWrapper = new LambdaQueryWrapper<>();
        userFollowWrapper.eq(ApUserFollow::getUserId, BaseContext.getCurrentId().intValue());
        List<ApUserFollow> userFollows = apUserFollowMapper.selectList(userFollowWrapper);
        cacheService.set(followKey, JSON.toJSONString(userFollows));*/
        //用户粉丝key设计: zset类型 key:业务前缀_用户id value:粉丝用户id score:当前时间戳
        String fansKey = UserConstants.USER_FANS_LIST + "_" + fansUserId;
        /* LambdaQueryWrapper<ApUserFan> userFanWrapper = new LambdaQueryWrapper<>();
        userFanWrapper.eq(ApUserFan::getUserId, userFollowDto.getAuthorId());
        List<ApUserFan> userFans = apUserFanMapper.selectList(userFanWrapper);
        cacheService.set(cancelFollowKey, JSON.toJSONString(userFans));*/
        if (operation == UserConstants.USER_FOLLOW_WEIGHT) {
            cacheService.zAdd(followKey, fansUserId, System.currentTimeMillis());
            cacheService.zAdd(fansKey, followUserId, System.currentTimeMillis());
        } else {
            cacheService.zRemove(followKey, fansUserId);
            cacheService.zRemove(fansKey, followUserId);
        }
    }

    //更新数据库关注与被关注
    private void updDbFollow(UserFollowDto userFollowDto, Long userId) {
        //用户关注
        userFollow(userFollowDto, userId);
        //取消用户关注
        cancelUserFollow(userFollowDto, userId);
    }

    /**
     * 取消用户关注
     *
     * @param userFollowDto 被关注者dto(被动关注)
     * @param userId        关注者id(主动关注)
     */
    private void cancelUserFollow(UserFollowDto userFollowDto, Long userId) {
        Integer followId = userFollowDto.getAuthorId();
        //查找关注列表和粉丝列表是否有用户
        ApUserFollow userFollow = getUserFollow(userId.intValue(), followId);
        ApUserFan userFan = getUserFan(followId, userId.intValue());
        if (userFollow == null || userFan == null) {
            return;
        }
        //如果取消状态删除关注表的粉丝表数据
        if (userFollowDto.getOperation() == UserConstants.USER_CANCEL_FOLLOW_WEIGHT) {
            //删除关注者的关注信息
            LambdaQueryWrapper<ApUserFollow> userFollowWrapper = new LambdaQueryWrapper<>();
            userFollowWrapper.eq(ApUserFollow::getFollowId, userFollowDto.getAuthorId())
                    .eq(ApUserFollow::getUserId, userId.intValue());
            apUserFollowMapper.delete(userFollowWrapper);
            //删除被关注的粉丝信息
            LambdaQueryWrapper<ApUserFan> userFanWrapper = new LambdaQueryWrapper<>();
            userFanWrapper.eq(ApUserFan::getFansId, userId.intValue())
                    .eq(ApUserFan::getUserId, userFollowDto.getAuthorId());
            apUserFanMapper.delete(userFanWrapper);
        }
    }

    /**
     * 用户关注
     *
     * @param userFollowDto 被关注者dto(被动关注)
     * @param userId        关注者id(主动关注)
     */
    private void userFollow(UserFollowDto userFollowDto, Long userId) {
        //查询当前用户下关注列表是否有此用户
        ApUserFollow apUserFollow = getUserFollow(userId.intValue(), userFollowDto.getAuthorId());
        //查询当前粉丝列表下是否有此用户
        ApUserFan apUserFan = getUserFan(userFollowDto.getAuthorId(), userId.intValue());
        //关注用户和粉丝用户:为了在关注表和粉丝表插入记录时,获取当前用户的昵称
        LambdaQueryWrapper<ApUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(ApUser::getId, userId.intValue());
        ApUser user = this.getOne(userWrapper);
        //如果是关注状态向关注表和粉丝表添加数据
        //关注表插入数据
        if (userFollowDto.getOperation() == UserConstants.USER_FOLLOW_WEIGHT
                && apUserFollow == null) {
            apUserFollow = new ApUserFollow();
            apUserFollow.setUserId(userId.intValue());//关注者id(主动关注)
            apUserFollow.setFollowId(userFollowDto.getAuthorId());//被关注者id(被关注)
            apUserFollow.setFollowName(user.getName());//被关注者昵称
            apUserFollow.setCreatedTime(new Date());
            apUserFollowMapper.insert(apUserFollow);
        }
        //粉丝表插入数据
        if (userFollowDto.getOperation() == UserConstants.USER_FOLLOW_WEIGHT
                && apUserFan == null) {
            apUserFan = new ApUserFan();
            apUserFan.setUserId(userFollowDto.getAuthorId());//被关注者id(被关注)
            apUserFan.setFansId(userId.intValue());//粉丝id
            apUserFan.setFansName(user.getName());//粉丝昵称
            apUserFan.setCreatedTime(new Date());
            apUserFanMapper.insert(apUserFan);
        }
    }

    /**
     * <h3>查询当前用户粉丝列表下是否有此用户</h3><br>
     * 查找流程:<br>
     * select * from ap_user_fan where user_id = userId and fans_id = fanid
     *
     * @param userId 粉丝用户
     * @param fanId  粉丝列表用户
     * @return 返回粉丝记录信息
     */
    private ApUserFan getUserFan(Integer userId, Integer fanId) {
        LambdaQueryWrapper<ApUserFan> userFanWrapper = new LambdaQueryWrapper<>();
        userFanWrapper.eq(ApUserFan::getUserId, userId)
                .eq(ApUserFan::getFansId, fanId);
        ApUserFan apUserFan = apUserFanMapper.selectOne(userFanWrapper);
        return apUserFan;
    }

    /**
     * <h3>查询当前用户关注列表下是否有此用户</h3><br>
     * 查找流程:<br>
     * select * from ap_user_follow where user_id = userId and follow_id = followId
     *
     * @param userId   关注者用户
     * @param followId 关注列表用户
     * @return 关注者
     */
    @Override
    public ApUserFollow getUserFollow(Integer userId, Integer followId) {
        //参数校验
        if (followId == null) {
            return null;
        }
        LambdaQueryWrapper<ApUserFollow> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ApUserFollow::getUserId, userId)
                .eq(ApUserFollow::getFollowId, followId);
        ApUserFollow apUserFollow = apUserFollowMapper.selectOne(wrapper);
        return apUserFollow;
    }

    /**
     * 根据dto条件查询app端用户信息
     *
     * @param userDto 前端dto查询条件
     * @return app用户信息
     */
    @Override
    public ApUser getUser(UserDto userDto) {
        if (userDto != null) {
            return apUserMapper.selectUserByCondition(userDto);
        } else {
            return null;
        }
    }
}




